
/*
 * @author Adley, Butcher, and Sanders
 * CSC 285 Final Project
 */

package tetris;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
import java.util.Stack;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;

public final class TetrisGame {
    
    private boolean[][] shapeArray;
    private ShapePanel[][] panels;
//    private final Color[][] colorArray;
    private TileShape[] shapes;
    private final Timer timer;
    private TileShape currentShape;
    private Stack<TileShape> stack;
    int shapeX, shapeY;
    private int delay = 1050;
    private ArrayList<Integer> currentShapeCoorX;
    private ArrayList<Integer> currentShapeCoorY;
    private JPanel panel;

    private final int Rows = 15; //y
    private final int Cols = 10; //x
    private int[] rotations = {0,1,2,3};
    private int rotation = 0;

    private final Color baseColor = Color.BLUE;
    private boolean[][] filledSpaces;
    
    // Decides if able to move
    private boolean move;
    
    private BoardFrame frame;
     
    public TetrisGame(){
        
        currentShapeCoorX = new ArrayList();
        currentShapeCoorY = new ArrayList();

        
        shapeArray = new boolean[Rows][Cols]; 
//        colorArray = new Color[row][col];
       
//        panels[0][0].filled();
        TileShape I = TileShape.ShapeI;
        TileShape L = TileShape.ShapeL;
        TileShape J = TileShape.ShapeJ;
        TileShape O = TileShape.ShapeO;
        TileShape Z = TileShape.ShapeZ;
        TileShape S = TileShape.ShapeS;
        TileShape T = TileShape.ShapeT;
        shapes = new TileShape[]{I,L,J,O,Z,S,T};
        Random rand = new Random();
        stack = new Stack();
        addShapeToStack();
        frame = new BoardFrame(this);
        panels = frame.getPanel();
        
        filledSpaces = new boolean[Rows][Cols];
        for (int r = 0; r < Rows; r++) {
            for (int c = 0; c < Cols; c++) {
                filledSpaces[r][c] = false;
            }
        }
        spawnShape();
//        System.out.println("stack: "+stack.peek());
        
        
        
        timer = new Timer(delay, new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent ae) {
                for (int i = 0; i < Rows; i++)
                {
                    for (int j = 0; j < Cols; j++)
                        System.out.print(filledSpaces[i][j]);
                    System.out.println("");
                }
                    moveDown();

            }            
        });

        timer.start();    
    }
    
    public void addShapeToStack(){
        Random rand = new Random();
        stack.push(shapes[rand.nextInt(shapes.length)]);
    }
    
    public boolean[][] getShapeArray(){
        return shapeArray;
    }
    
//    public Color[][] getColorArray(){
//        return colorArray;
//    }
    public boolean fillCheck(){
       move = false;
        //Checks if end of Board   
        for (int i = 0; i < currentShapeCoorY.size(); i++) {
            if(currentShapeCoorY.get(i) == Rows-1){
                System.out.println("Out of bounds");
                for (int coor = 0; coor < currentShapeCoorY.size(); coor++) //get everything in this array and put in filledSpaces array
                    {
                        filledSpaces[currentShapeCoorY.get(coor)][currentShapeCoorX.get(coor)] = true;
                    }
                move = false;
            }else{
                //this for loop check underneath the shape to see if there is a shape in the filledSpaces array 
                 if(filledSpaces[currentShapeCoorY.get(i)+1][currentShapeCoorX.get(i)] == true || filledSpaces[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)] == true){ 
                    for (int coor = 0; coor < currentShapeCoorY.size(); coor++) //get everything in this array and put in filledSpaces array
                    {
                        filledSpaces[currentShapeCoorY.get(coor)][currentShapeCoorX.get(coor)] = true;

                    }System.out.println("Smile");move = false;
                 }
                else{
                    move = true;
                }
            }
        }
       //The shape has reached the bottom and with nothing being true(no shape underneath) 
//       for (int i = 0; i < currentShapeCoorY.size(); i++) {
//            if(currentShapeCoorY.get(i) ==  Rows-1){
//                 for (int coor = 0; coor < currentShapeCoorY.size(); coor++) //get everything in this array and put in filledSpaces array
//                {
//                    filledSpaces[currentShapeCoorY.get(coor)][currentShapeCoorX.get(coor)] = true;
//                     move = false;
//                }
//            }else{
//                move = true;
//            }
//        }
        System.out.println("move: " + move);
       return move;
       
    }
    //place where stack of shapes//ignore????

    public void moveLeft(){
        boolean min = false;
        for (int x = 0;x  < currentShapeCoorX.size(); x++) {
            if(currentShapeCoorX.get(x) == 0){
                System.out.println("Out of bounds");
                min = true;
            }
        }
        if(!min)
        {
                for (int i = 0; i < currentShapeCoorY.size(); i++) {
                    shapeArray[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)] = false;
                    panels[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)].setFill(false);
                }

                 for (int i = 0; i < currentShapeCoorY.size(); i++) {    
                    currentShapeCoorX.set(i, currentShapeCoorX.get(i)-1);
                    shapeArray[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)] = true;
                    panels[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)].setFill(true);
                    panels[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)].setColor(currentShape.getColor());
                    System.out.println("Y: "+currentShapeCoorY.get(i)+" X: " +currentShapeCoorX.get(i));
                }
            shapeX--;
        }
        
    } 

    public Color getBaseColor(){
        return baseColor;
    }
    
    public void moveRight(){
         boolean max = false;
         for (int x = 0; x  < currentShapeCoorX.size(); x++) {
                if(currentShapeCoorX.get(x) == Cols-1){
                    System.out.println("Out of Bounds");
                    max = true;
                }
         }

         if(!max){
            for (int i = 0; i < currentShapeCoorY.size(); i++) {
                shapeArray[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)] = false;
                panels[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)].setFill(false);
            }

            for (int i = 0; i < currentShapeCoorY.size(); i++) {    
                currentShapeCoorX.set(i, currentShapeCoorX.get(i)+1);
                shapeArray[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)] = true;
                panels[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)].setFill(true);
                panels[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)].setColor(currentShape.getColor());
                System.out.println("Y: "+currentShapeCoorY.get(i)+" X: " +currentShapeCoorX.get(i));
                }
            shapeX++;
        }
    }

    
    public void fullDrop(){
          moveDown();

    }
    
   
    
    
    public void moveDown(){
        if(fillCheck()){
        
        //Take current shape and unshow
        for (int i = 0; i < currentShapeCoorY.size(); i++) {    
            shapeArray[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)] = false;
            panels[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)].setFill(false) ;
        }
        //Take shape and show
         for (int i = 0; i < currentShapeCoorY.size(); i++) {
            currentShapeCoorY.set(i, currentShapeCoorY.get(i)+1);
            shapeArray[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)] = true;
            panels[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)].setFill(true);
            panels[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)].setColor(currentShape.getColor());
    //            colorArray[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)] = baseColor;
            
                  
            System.out.println("Y: "+currentShapeCoorY.get(i)+" X: " +currentShapeCoorX.get(i));

        }
        
        shapeY++;

        }
        else{
            System.out.println("reached bottom");

            addShapeToStack();
            rowCheck();
            spawnShape();
            
        }

    }
    
    public void decreaseDelay(){
        delay++;
        timer.setDelay(delay);
        timer.start();
    }
    
    public void rotate(){
        for (int i = 0; i < currentShapeCoorY.size(); i++) {
            shapeArray[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)] = false;
            panels[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)].setFill(false);
        }    
        System.out.println("in rotate");
        //get number 0 - 3
        rotation++;
        int rot =  rotation % (rotations.length);
        int r = rotations[rot];
        currentShapeCoorY = new ArrayList();
        currentShapeCoorX = new ArrayList();
       
        int count = 0; 
         for (int y = 0; y < 4; y++){ 
            for (int x = 0; x < 4; x++) {
//                  panels[(y)+shapeY][(x)+shapeX].setFill(bool[0][count]);
                  boolean[][] bool = currentShape.getShape();                  
//                  shapeArray[(y)+shapeY][(x)+shapeX] = bool[r][count];
                
                  System.out.println("bool: " + bool[y][x]);
                  
                    if(bool[r][count] == true){
//                        colorArray[(y)+shapeY][(x)+shapeX] = currentShape.getColor();
                        
                        currentShapeCoorY.add(y+shapeY);
                        currentShapeCoorX.add(x+shapeX);
                       
                    }
              count++;      
            }
            
         } 
         System.out.println("CoorY: " + currentShapeCoorY + "\n" +
                        " CoorX: " + currentShapeCoorX);
         for (int i = 0; i < currentShapeCoorY.size(); i++) {
//            currentShapeCoorY.set(i, currentShapeCoorY.get(i)+1);
            shapeArray[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)] = true;
            panels[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)].setFill(true);
            panels[currentShapeCoorY.get(i)][currentShapeCoorX.get(i)].setColor(currentShape.getColor());
            System.out.println("Y: "+currentShapeCoorY.get(i)+" X: " +currentShapeCoorX.get(i));
        }

    }
    //method that displays the shape
    private void spawnShape(){
        
        shapeX = 3;
        shapeY = 0;
        currentShapeCoorY = new ArrayList();
        currentShapeCoorX = new ArrayList();
        
        currentShape = stack.pop();
        boolean[][] bool = currentShape.getShape();
        System.out.println("Shape: "+ currentShape);
        int count = 0; 
        for (int y = 0; y < 4; y++){ 
            for (int x = 0; x < 4; x++) {
//                  panels[(y)+shapeY][(x)+shapeX].setFill(bool[0][count]);
                 
                 
                 
                  shapeArray[(y)+shapeY][(x)+shapeX] = bool[0][count];
                  panels[(y)+shapeY][(x)+shapeX].setColor(currentShape.getColor());
                 
                    if(bool[0][count] == true){
//                        colorArray[(y)+shapeY][(x)+shapeX] = currentShape.getColor();
                         currentShapeCoorY.add(y+shapeY);
                         currentShapeCoorX.add(x+shapeX);
                    }                   
                    
//                  System.out.println("mod1: " + x);
//                  System.out.println("mod2: " + y);
//                  System.out.println("Bool: " + bool[0][row]);
//                  System.out.println("Color" + currentShape.getColor());
//                  
                  count++;
            }            
            }
        for (int y = 0; y < currentShapeCoorY.size(); y++){ 
            if(shapeArray[currentShapeCoorY.get(y)][currentShapeCoorX.get(y)] == filledSpaces[currentShapeCoorY.get(y)][currentShapeCoorX.get(y)]){
                      gameover();
            }
         System.out.println("CoorY: " + currentShapeCoorY + "\n" +
                 " CoorX: " + currentShapeCoorX);

        }
    }
//    
//    public boolean finish(){
//        boolean finished = false;
//        int colnumber = 0;
//        int countblankcol = 0;
//        int countblankrows = 0;
//        for (int row = 0; row < Rows; row++) {//if each row is not empty game over
//            for (int col = 0; col < Cols; col++) {
//                countblankcol = 0;
//                if(filledSpaces[row][col] == true){
//                    countblankcol = 1;
//                    countblankrows = row;
//                }
//            }
////            System.out.println("count: " + countblankrows);
//        }
//        if(countblankrows == Rows){
//            System.out.println("A column is full. GAME OVER!!!!");
//            finished = true;
//        }
//        return finished;
//    }
    
    public void gameover(){
        timer.stop();
        frame.dispose();
        
        JOptionPane.showMessageDialog(panel, "GameOver");
        
        TetrisGame game = new TetrisGame();

       
        
    }
    
    public void rowCheck(){
        int rownumber = 0;
        int countblankcols = 0;
        for (int row = 0; row < Rows; row++) {
            for (int col = 0; col < Cols; col++) {
                if(filledSpaces[row][col] == true){
                    countblankcols++;
                }else{
                    countblankcols=0;
                }
            }
            System.out.println("count: " + countblankcols);
            if(countblankcols >= Cols){
                rownumber = row;
                System.out.println("clearing rows");
                //clear row
                for (int col1 = 0; col1 < Cols; col1++) {
                    countblankcols = 0;
                    filledSpaces[row][col1] = false;
                    shapeArray[row][col1]= false;
                    panels[row][col1].setFill(false);
                }
                System.out.println("Rownumber: " + rownumber);
                for (int movY = rownumber; movY > 0; movY--) {
                    for (int col2 = 0; col2 < Cols; col2++) {
                        System.out.println("movX:"+col2+", "+"movY: "+movY);
                        filledSpaces[movY][col2] = filledSpaces[movY-1][col2];
                        shapeArray[movY][col2] = shapeArray[movY-1][col2];
                        panels[movY][col2].setFill(panels[movY-1][col2].isfilled());
                    }
                    
                }
            }
        }
    }
    
    public TileShape getCurrentShape(){
            return currentShape;
    }
    
}
